#ifndef _M_DATA
#define _M_DATA
#include <iostream>
#include "util.hpp"
#include <unordered_map>
#include "config.hpp"
#include <pthread.h>
namespace tqbcloud
{
    typedef struct BackupInfo
    {
        bool _pack_flag;
        time_t _mtime;
        time_t _atime;
        size_t _fsize;
        std::string _realpath;
        std::string _url;
        std::string _packpath;
        bool NewBackupInfo(const std::string &realpath)
        {
            tqbcloud::Fileutil fu(realpath);
            _pack_flag = false;
            _fsize = fu.FileSize();
            _mtime = fu.Lastmotime();
            _atime = fu.Lastacctime();
            _realpath = realpath;
            tqbcloud::Config *f = tqbcloud::Config::getinstance();
            _packpath = f->GetPackDir() + fu.FileName() + f->GetArcSuffix();
            _url = f->GetURLPrefix() + fu.FileName();
        }
    } BackupInfo;
    class DataManager
    {
    private:
        tqbcloud::Fileutil _backup_file;
        pthread_rwlock_t _rwlock;
        std::unordered_map<std::string, BackupInfo> _table;
    public:
        DataManager(const std::string backup_file)
        :_backup_file(backup_file)
        {
            pthread_rwlock_init(&_rwlock,nullptr);
            if(pthread_rwlock_init(&_rwlock,nullptr)!=0){
                std::cout<<"rwlock_init erro"<<std::endl;
            }
            InitLoad();
        }
        bool InitLoad()// 初始化程序运行时从文件读取数据
        {

            tqbcloud::Fileutil fu(_backup_file);
            if(fu.Exists()==false){
                std::cout<<"no backupfile to load"<<std::endl;
                return false;
            }
            std::string body;
            fu.GetContent(&body);
            std::cout<<"load body:"<<body<<std::endl;
            Json::Value vv;
            tqbcloud::JsonUtil::UnSerialize(body,&vv);
            for(auto v:vv){
                BackupInfo info;
                info._atime=v["_atime"].asInt();
                info._mtime=v["_mtime"].asInt();
                info._fsize=v["_fsize"].asInt();
                info._realpath=v["_realpath"].asString();
                info._url=v["_url"].asString();
                info._packpath=v["_packpath"].asString();
                Insert(info._url,info);
            }
            return true;
            
        }
        bool Storage()// 每次有信息改变则需要持久化存储一次
        {
            Json::Value vv;
            for(auto i:_table){
                Json::Value v;
                v["_pack_flag"]=i.second._pack_flag;
                v["_mtime"]=(Json::UInt64)i.second._mtime;
                v["_atime"]=(Json::UInt64)i.second._atime;
                v["_fsize"]=(Json::UInt64)i.second._fsize;
                v["_realpath"]=i.second._realpath;
                v["_url"]=i.second._url;
                v["_packpath"]=i.second._packpath;
                vv.append(v);
            }
            std::string body;
            tqbcloud::JsonUtil::Serialize(vv,&body);
            tqbcloud::Fileutil fu(_backup_file);
            fu.SetContent(&body);
           
        } 
        bool Insert(const std::string &key, const BackupInfo &val)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[key]=val;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;

        }
        bool Update(const std::string &key, const BackupInfo &val)
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[key]=val;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }
        //key值为URL
        bool GetOneByURL(const std::string &key, BackupInfo *info){
            pthread_rwlock_wrlock(&_rwlock);
            std::unordered_map<std::string, tqbcloud::BackupInfo>::iterator ret=_table.find(key);
            if(ret==_table.end()){
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            *info=ret->second;
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
        bool GetOneByRealPath(const std::string &key, BackupInfo *info){
            pthread_rwlock_wrlock(&_rwlock);
            for(auto i:_table){
                if(i.second._realpath==key){
                    *info=i.second;
                    pthread_rwlock_unlock(&_rwlock);
                    return true;
                }
            }
            pthread_rwlock_unlock(&_rwlock);
            return false;
            
        }
        bool GetAll(std::vector<BackupInfo> *arry){
            pthread_rwlock_wrlock(&_rwlock);
            for(auto i:_table){
                arry->push_back(i.second);
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
        ~DataManager(){
            if(pthread_rwlock_destroy(&_rwlock)!=0){
                std::cout<<"rwlock_destroy erro"<<std::endl;
            }
        }
    };
}
#endif